package com.bocloud.cmp.driver.providers.vmware;

import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bocloud.cmp.driver.providers.SnapshotDriver;
import com.bocloud.cmp.driver.utils.AssembleTools;
import com.bocloud.cmp.model.SnapshotModel;
import com.bocloud.common.model.BsmResult;
import com.google.common.collect.Maps;
import com.vmware.vim25.VirtualMachineSnapshotTree;
import com.vmware.vim25.mo.HostSystem;
import com.vmware.vim25.mo.InventoryNavigator;
import com.vmware.vim25.mo.ManagedEntity;
import com.vmware.vim25.mo.Task;
import com.vmware.vim25.mo.VirtualMachine;
import com.vmware.vim25.mo.VirtualMachineSnapshot;

/**
 * vmware虚拟机快照操作接口实现类
 * 
 * @author weiwei
 *
 */
public class VmwareSnapshotDriver extends VmwareDriver implements SnapshotDriver {

	private static Logger logger = LoggerFactory.getLogger(VmwareSnapshotDriver.class);

	public VmwareSnapshotDriver() {
		super();
	}

	public VmwareSnapshotDriver(String endpoint, String username, String password) {
		super(endpoint, username, password);
	}

	@Override
	public BsmResult list() {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * 删除快照解决思路：1：首先获取虚拟机各个快照树的最下面一层的子节点（本身不含子节点），存入Map中；
	 * 2.取得虚拟机所有的快照，如果快照在Map中，即表明该快照没有子节点了，不再获取该快照的子节点； 3.快照一一与传过来的值进行比对，若对应则删除
	 */
	@Override
	public BsmResult remove(SnapshotModel model) {
		try {
			ManagedEntity entity = this.getServiceInstance().getSearchIndex().findByUuid(null, model.getInstanceId(),
					true, true);
			VirtualMachine machine = (VirtualMachine) entity;
			// 存储没有子节点的快照（即最下面一层的快照）
			Map<String, String> lastest = Maps.newHashMap();
			//
			Map<String, String> snapshotMap = Maps.newHashMap();
			// 获取虚拟机快照树（可能是多个）根节点
			VirtualMachineSnapshotTree[] trees = machine.getSnapshot().getRootSnapshotList();
			VirtualMachineSnapshot[] vmSnapshotArray = machine.getRootSnapshot();
			// 获取快照树最下面一层的快照
			traverseSnapshotTree(trees, lastest, snapshotMap);
			boolean result = deleteSnapshot(vmSnapshotArray, lastest, snapshotMap.get(model.getSnapshotId()));
			return result ? new BsmResult(true, "删除成功") : new BsmResult(false, "删除失败");
		} catch (Exception e) {
			logger.error("sync info error:", e);
			return new BsmResult(false, "删除失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	/**
	 * 删除快照：Map中存放的是快照树最下面的一层快照（没有子节点的快照）
	 * 
	 * @param rootSnapshots
	 * @param lastest
	 * @param value
	 * @return
	 * @throws Exception
	 */
	private boolean deleteSnapshot(VirtualMachineSnapshot[] snapshots, Map<String, String> lastest, String value)
			throws Exception {
		if (null != snapshots) {
			for (VirtualMachineSnapshot snapshot : snapshots) {
				if (value.equals(snapshot.getMOR().getVal())) {
					Task task = snapshot.removeSnapshot_Task(false);
					return (task.waitForTask().equals(Task.SUCCESS)) ? true : false;
				} else {
					// 若latest（Map类型）不包含此快照的getVal值，即此快照含有子节点
					if (!lastest.containsKey(snapshot.getMOR().getVal())) {
						// 快照含有子节点，继续遍历比对删除
						boolean reseult = deleteSnapshot(snapshot.getChildSnapshot(), lastest, value);
						if (reseult) {
							return reseult;
						}
					}
				}
			}
		}
		return false;
	}

	/**
	 * 虚拟机快照获取出来是一个树的形式，此方法取到快照树最下面一层的快照，即没有子节点的快照，存入Map中
	 * 
	 * @param trees
	 * @param latest
	 */
	private void traverseSnapshotTree(VirtualMachineSnapshotTree[] trees, Map<String, String> latest,
			Map<String, String> snapshotMap) {
		if (null != trees) {
			for (VirtualMachineSnapshotTree tree : trees) {
				snapshotMap.put(tree.getId().toString(), tree.getSnapshot().getVal());
				if (null != tree.getChildSnapshotList()) {
					traverseSnapshotTree(tree.getChildSnapshotList(), latest, snapshotMap);
				} else {
					// 如果该快照不含子节点，存入latest中
					latest.put(tree.getSnapshot().getVal(), tree.getName());
				}
			}
		}

	}

	@Override
	public BsmResult detail(SnapshotModel model) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult modify(SnapshotModel model) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public BsmResult revert(SnapshotModel model) {
		try {
			ManagedEntity entity = this.getServiceInstance().getSearchIndex().findByUuid(null, model.getInstanceId(),
					true, true);
			VirtualMachine machine = (VirtualMachine) entity;
			// 存储没有子节点的快照（即最下面一层的快照）
			Map<String, String> lastest = Maps.newHashMap();
			Map<String, String> snapshotMap = Maps.newHashMap();
			// 获取虚拟机快照树（可能是多个）根节点
			VirtualMachineSnapshotTree[] trees = machine.getSnapshot().getRootSnapshotList();
			VirtualMachineSnapshot[] snapshots = machine.getRootSnapshot();
			// 获取快照树最下面一层的快照
			traverseSnapshotTree(trees, lastest, snapshotMap);
			// 获取宿主机
			ManagedEntity hostEntity = new InventoryNavigator(this.getRootFolder()).searchManagedEntity("HostSystem",
					model.getHostName());
			boolean result = revertSnapshot(snapshots, lastest, snapshotMap.get(model.getSnapshotId()),
					(HostSystem) hostEntity);
			if (result) {
				entity = this.getServiceInstance().getSearchIndex().findByUuid(null, model.getInstanceId(), true, true);
				return new BsmResult(true, AssembleTools.getInstance().convertServer((VirtualMachine) entity), "恢复成功");
			}
			return new BsmResult(false, "恢复失败");
		} catch (Exception e) {
			logger.error("revert snapshot error:", e);
			return new BsmResult(false, "恢复失败");
		} finally {
			this.getServiceInstance().getServerConnection().logout();
		}
	}

	/**
	 * 恢复快照
	 * 
	 * @param rootSnapshots
	 * @param value
	 * @return
	 * @throws Exception
	 */
	private boolean revertSnapshot(VirtualMachineSnapshot[] snapshots, Map<String, String> lastest, String value,
			HostSystem host) throws Exception {
		if (null != snapshots && null != value) {
			for (VirtualMachineSnapshot snapshot : snapshots) {
				if (value.equals(snapshot.getMOR().getVal())) {
					Task task = snapshot.revertToSnapshot_Task(host);
					return (task.waitForTask().equals(Task.SUCCESS)) ? true : false;
				} else {
					if (!lastest.containsKey(snapshot.getMOR().getVal())) {
						boolean result = revertSnapshot(snapshot.getChildSnapshot(), lastest, value, host);
						if (result) {
							return result;
						}
					}
				}
			}
		}
		return false;
	}

}
